package com.aaron.socket.server;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.OpenOption;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;

public class NIOServerThread extends Thread{
	
	private int port;
	private ByteBuffer readBuffer;
	private Selector selector;
	private ServerSocketChannel listenChannel;
	
	public NIOServerThread(int port){
		this.port = port;
		
	}
	
	
	@Override
	public void run(){
		readBuffer = ByteBuffer.allocate(1024);
		try {
			selector = Selector.open();
			listenChannel   = ServerSocketChannel.open();
			listenChannel.configureBlocking(false);
			listenChannel.socket().bind(new InetSocketAddress("localhost",port));
			
			//注册建立连接事件
			listenChannel.register(selector, SelectionKey.OP_ACCEPT);
			
			//循环检查Selector中事件
			System.out.println("开始监听连接...");
			while(!this.isInterrupted()){
				int keyCount = selector.select();
				if(keyCount <= 0){
					continue;
				}
				Set<SelectionKey> selectorKeys = selector.selectedKeys();
				Iterator<SelectionKey> it = selectorKeys.iterator();
				while(it.hasNext()){
					
					SelectionKey key = (SelectionKey) it.next();
					
					//队列中有接受（ACCEPT）连接事件
					if((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT){
						
						ServerSocketChannel ch = (ServerSocketChannel)key.channel();
						System.out.println("建立连接："+ch.getLocalAddress());
						
						//连接建立，新建一个专门用于数据传输的channel
						SocketChannel dataChannel =  ch.accept();
						FileChannel fileChannel = new FileOutputStream(new File("./rev_"+new Random().nextInt(1000)+".file")).getChannel();
						
						dataChannel.configureBlocking(false);
						
						
						//注册数据传输通道的可读数据事件,可对应的文件Channel
						dataChannel.register(selector, SelectionKey.OP_READ,fileChannel);
						
						
						//事件处理完毕，在队列中清除
						it.remove();
					}
					
					
					//队列中有数据可读（READ）事件
					if((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ){
						
						System.out.println("缓冲区数据可读");
						
						SocketChannel dataChannel = (SocketChannel) key.channel();
						FileChannel   fileChannel = (FileChannel) key.attachment();
						try{
						
							while(true){
								readBuffer.clear();
								int len = dataChannel.read(readBuffer);
								if(len <= 0){
									fileChannel.close();
									break;
								}
								readBuffer.flip();
								fileChannel.write(readBuffer);
								
								//返回客户端消息
								ByteBuffer writeBuffer = ByteBuffer.allocate(256);
								writeBuffer.put(new String("接收成功!").getBytes("GBK"));
								writeBuffer.flip();
								dataChannel.write(writeBuffer);
								it.remove();
								
							}
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
							fileChannel.close();
							System.out.println("连接中断!");
						}
						
					}
					
				}
				
				
				
				
			}
			
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("创建Selector/Channel/FileChannel失败！");
			return;
		}
		finally{
			if(null != selector){
				try {
					selector.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				    System.out.println("关闭Selector失败！");
				}
			}
			
			
			if(null != listenChannel){
				try {
					listenChannel.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					System.out.println("关闭Channel失败！");
				}
			}
			
		    if(null != readBuffer){
		    	//主动调用垃圾回收，清空堆外内存
		    	//System.gc();
		    }
			
			
		}
		
		
		
		
		
	}
	
	
	
}
